﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Mvc.Html;

namespace Infrastructure.Web.Mvc.Extensions
{
    public static partial class HtmlHelperExtensions
    {
        public static MvcHtmlString PartialFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expr, string viewName)
        {
            string name = ExpressionHelper.GetExpressionText(expr);
            object model = ModelMetadata.FromLambdaExpression(expr, helper.ViewData).Model;
            return helper.Partial(viewName, model, new ViewDataDictionary(helper.ViewData) { TemplateInfo = new TemplateInfo { HtmlFieldPrefix = name } });
        }

        public static void RenderAction<TController>(this HtmlHelper helper, Expression<Action<TController>> action) where TController : Controller
        {
            RouteValueDictionary routeValuesFromExpression = Utils.GetRouteValuesFromExpression<TController>(action);
            helper.RenderRoute(routeValuesFromExpression);
        }

        public static void RenderRoute(this HtmlHelper helper, RouteValueDictionary routeValues)
        {
            RouteData routeData = new RouteData();
            foreach (KeyValuePair<string, object> pair in routeValues)
            {
                routeData.Values.Add(pair.Key, pair.Value);
            }
            HttpContextBase httpContext = helper.ViewContext.HttpContext;
            RequestContext context = new RequestContext(httpContext, routeData);
            new RenderActionMvcHandler(context).ProcessRequestInternal(httpContext);
        }

        public static MvcHtmlString RenderHtml(this HtmlHelper helper, string strValue)
        {
            return new MvcHtmlString(strValue);
        }

        public static Language LanguageUrl(this HtmlHelper helper, string cultureName,
               string languageRouteName = "lang", bool strictSelected = false)
        {
            // set the input language to lower
            cultureName = cultureName.ToLower();
            // retrieve the route values from the view context
            var routeValues = new RouteValueDictionary(helper.ViewContext.RouteData.Values);
            // copy the query strings into the route values to generate the link
            var queryString = helper.ViewContext.HttpContext.Request.QueryString;
            foreach (string key in queryString)
            {
                if (queryString[key] != null && !string.IsNullOrWhiteSpace(key))
                {
                    if (routeValues.ContainsKey(key))
                    {
                        routeValues[key] = queryString[key];
                    }
                    else
                    {
                        routeValues.Add(key, queryString[key]);
                    }
                }
            }
            var actionName = routeValues["action"].ToString();
            var controllerName = routeValues["controller"].ToString();
            // set the language into route values
            routeValues[languageRouteName] = cultureName;
            // generate the language specify url
            var urlHelper = new UrlHelper(helper.ViewContext.RequestContext, helper.RouteCollection);
            var url = urlHelper.RouteUrl("Localization", routeValues);
            // check whether the current thread ui culture is this language
            var current_lang_name = System.Threading.Thread.CurrentThread.CurrentUICulture.Name.ToLower();
            var isSelected = strictSelected ?
                current_lang_name == cultureName :
                current_lang_name.StartsWith(cultureName);
            return new Language()
            {
                Url = url,
                ActionName = actionName,
                ControllerName = controllerName,
                RouteValues = routeValues,
                IsSelected = isSelected
            };
        }
        public static MvcHtmlString LanguageSelectorLink(this HtmlHelper helper,
              string cultureName, string selectedText, string unselectedText,
              IDictionary<string, object> htmlAttributes, string languageRouteName = "lang", bool strictSelected = false)
        {
            var language = helper.LanguageUrl(cultureName, languageRouteName, strictSelected);
            var link = helper.RouteLink(language.IsSelected ? selectedText : unselectedText,
                "Localization", language.RouteValues, htmlAttributes);
            return link;
        }
    }

    internal class RenderActionMvcHandler : MvcHandler
    {
        public RenderActionMvcHandler(RequestContext context)
            : base(context)
        {
        }

        protected override void AddVersionHeader(HttpContextBase httpContext)
        {
        }

        public void ProcessRequestInternal(HttpContextBase httpContext)
        {
            base.ProcessRequest(httpContext);
        }
    }
    public class Language
    {
        public string Url { get; set; }
        public string ActionName { get; set; }
        public string ControllerName { get; set; }
        public RouteValueDictionary RouteValues { get; set; }
        public bool IsSelected { get; set; }

        public MvcHtmlString HtmlSafeUrl
        {
            get
            {
                return MvcHtmlString.Create(Url);
            }
        }
    }

}
